package com.learning.optimize.jdk.clazz;

import com.learning.optimize.jdk.annotation.CustomAnnotation;

import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * ClassName: ClassReflect
 * Description: Class 类
 * Date: 2018/7/17 22:38 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class ClassReflect {

    public static void main(String[] args) {
//        test();
//        test3();
//        test4();
        test6();
        test7();
    }

    /**
     * static语句，会在类第一次被加载时执行
     */
    public static void test() {
        print("inside main");
        new Candy();
        print("After creating Candy");
        try {
            Class.forName("com.learning.optimize.jdk.clazz.Gum");
        } catch (ClassNotFoundException e) {
            print("Couldn't find Gum");
        }
        print("After Class.forName(\"com.learning.optimize.jdk.reflect.Gum\")");
        new Cookie();
        print("After creating Cookie");

        // 不会加载
        Class<Gum> gumClass = Gum.class;

        /*输出
        inside main
        Loading Candy
        After creating Candy
        Loading Gum
        After Class.forName("com.learning.optimize.jdk.reflect.Gum")
        Loading Cookie
        After creating Cookie
        */
    }

    /**
     * Class 加载方法
     * 1、使用forName获取Class对象的引用会触发类的初始化
     * 2、需要捕获一个名称为ClassNotFoundException的异常，
     * 因为forName() 方法在编译器是无法检测到其传递的字符串对应的类是否存在的，
     * 只能在程序运行时进行检查，如果不存在就会抛出ClassNotFoundException异常
     */
    public static void test2() {
        try {
            //通过 Class.forName 获取 Gum 类的 Class 对象
            Class<?> clazz = Class.forName("com.learning.optimize.jdk.clazz.Gum");
            print("forName = clazz: " + clazz.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //通过实例对象获取Gum的Class对象
        Gum gum = new Gum();
        Class<?> clazz2 = gum.getClass();
        print("new = clazz2: " + clazz2.getName());

        Class<Gum> clazz3 = Gum.class;
        print("Gum.class 字面常量: " + clazz3.getName());


        print(clazz2 == clazz3);

        /*
        Loading Gum // 触发类的初始化
        forName=clazz: com.learning.optimize.jdk.reflect.Gum
        new=clazz2: com.learning.optimize.jdk.reflect.Gum
        */
    }

    /**
     * Class字面常量
     * 使用字面常量的方式获取Class对象的引用不会触发类的初始化
     */
    public static void test3() {
        Class clazz = Gum.class;
        print("Gum.class 字面常量: " + clazz.getName());

        /*
         * Gum.class 字面常量: com.learning.optimize.jdk.reflect.Gum
         * */
    }

    /**
     * 基本类型与包装类
     */
    static void test4() {
        print(String.class.isPrimitive());
        print(int.class.isPrimitive());
        print(int[].class.isPrimitive());
        print(int[].class.isArray());

        // 这边是 false
        print(int.class == Integer.class);
        // 常量type代表包装类型的字节码
        print(int.class == Integer.TYPE);

        /*
            false
            true
            false
            true
            false
            true
        */
    }

    /**
     * 泛型化的Class
     */
    static void test5() {
        //没有泛型
        Class intClass = int.class;

        //带泛型的Class对象
        Class<Integer> integerClass = int.class;

        integerClass = Integer.class;

        //没有泛型的约束,可以随意赋值
        intClass = double.class;

        //编译期错误,无法编译通过
        //integerClass = double.class
    }


    static void test6() {
        Class<FruitsCookie> clazz = FruitsCookie.class;
        // getSuperclass(): 返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的超类的 Class
        // Object 类、一个接口、一个基本类型或 void，则返回 null。
        Class<? super FruitsCookie> superclass = clazz.getSuperclass();
        print(superclass.getName());

        // getGenericSuperclass() 返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。
        Type genericSuperclass = clazz.getGenericSuperclass();
        print(genericSuperclass instanceof ParameterizedType);
        // 获取父类的信息
        print(genericSuperclass.getTypeName());

        // 封装了父类及其注解（JDK1.8 新增）
        AnnotatedType annotatedSuperclass = clazz.getAnnotatedSuperclass();
        print(annotatedSuperclass instanceof AnnotatedParameterizedType);

        // 父类的信息
        Type type = annotatedSuperclass.getType();
        print(type instanceof ParameterizedType);
        print(type.getTypeName());


        /*
        com.learning.optimize.jdk.clazz.Cookie
        true
        com.learning.optimize.jdk.clazz.Cookie<com.learning.optimize.jdk.clazz.Fruits>
        true
        false
        com.learning.optimize.jdk.clazz.Cookie<com.learning.optimize.jdk.clazz.Fruits>
        */
    }

    /**
     * Type - ParameterizedType 简单理解
     */
    static void test7() {
        Class<FruitsCookie> clazz = FruitsCookie.class;

        // getGenericSuperclass() 返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。
        Type genericSuperclass = clazz.getGenericSuperclass();
        print(genericSuperclass instanceof ParameterizedType);
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;

        // 获取泛型的类型
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        Type actualTypeArgument = actualTypeArguments[0];
        System.out.println(actualTypeArgument.getTypeName());

        // 返回的是当前这个 ParameterizedType 的类型
        Type rawType = parameterizedType.getRawType();

        // Type getOwnerType()返回 Type 对象，表示此类型是其成员之一的类型。例如，如果此类型为 O<T>.I<S>，则返回 O<T> 的表示形式。
        // 如果此类型为顶层类型，则返回 null。
        Type ownerType = parameterizedType.getOwnerType();

    }

    private static void print(Object obj) {
        System.out.println(obj);
    }
}

class Candy {
    static {
        System.out.println("Loading Candy");
    }
}

class Gum {
    static {
        System.out.println("Loading Gum");
    }
}


class Cookie<T> {
    static {
        System.out.println("Loading Cookie");
    }
}

class FruitsCookie extends Cookie<Fruits> {

}

class Fruits {

}